import SparkMD5 from "spark-md5";
import request from "@/http/request";
/**
 * 计算文件的标识,取第处与最后一片进行hash
 * @param file 文件
 * @param chunkSize 分片大小
 * @returns
 */
const calculateHashSample = async (
  file: File,
  chunkSize: number = 1024 * 1024 * 5
): Promise<string> => {
  return await new Promise<string>((resolve, reject) => {
    const spark = new SparkMD5.ArrayBuffer();
    const reader = new FileReader();
    const size = file.size; //文件大小
    // 第一个5M，最后一个区块数据全要
    const chunks = [file.slice(0, chunkSize)];
    let cur = chunkSize;
    while (cur < size) {
      if (cur + chunkSize >= size) {
        // 最后一个区快
        chunks.push(file.slice(cur, cur + chunkSize));
      } else {
        // 中间的区块
        const mid = cur + chunkSize / 2;
        const end = cur + chunkSize;
        chunks.push(file.slice(cur, cur + 2));
        chunks.push(file.slice(mid, mid + 2));
        chunks.push(file.slice(end - 2, end));
      }
      cur += chunkSize;
    }
    // 中间的，取前中后各2各字节
    reader.readAsArrayBuffer(new Blob(chunks));
    reader.onload = (e) => {
      spark.append(e?.target?.result as ArrayBuffer);
      resolve(spark.end());
    };
  });
};
/**
 * 计算总共多个切片
 * @param file 文件
 * @param chunkSize 分片大小
 */
const setFileChunk = async (
  hash: string | undefined = "",
  file: File,
  chunkSize: number = 1024 * 1024 * 5
): Promise<any> => {
  return await new Promise<any>((resolve, reject) => {
    const chunkList = []; // 保存所有切片的数组
    const chunkListLength = Math.ceil(file.size / chunkSize);
    // 生成切片
    let currentChunk = 0; // 切片时的初始位置
    for (let i = 0; i < chunkListLength; i++) {
      const item = {
        chunkNumber: i + 1,
        totalChunks: chunkListLength,
        chunkSize: chunkSize,
        currentChunkSize: file.slice(currentChunk, currentChunk + chunkSize)
          .size,
        totalSize: file.size,
        file: file.slice(currentChunk, currentChunk + chunkSize),
        identifier: hash,
        filename: file.name,
        ralativepath: file.name,
      };
      currentChunk += chunkSize;
      chunkList.push(item);
    }
    resolve(chunkList);
  });
  // 1.计算总共多个切片
};
/**
 * 大文件分片上传处理
 * @param file 文件
 * @param [chunkSize] 分片大小
 * @param { function } funcCallback 返回结果
 * @returns
 *
 */
export async function uploadFile(
  file: File,
  chunkSize: number = 1024 * 1024 * 5,
  funcCallback: any,
  onUploadProgress: any
) {
  if (!file) return;
  //上传文件大小大于当前分布大小进行上传处理
  const options: any = {
    showProgress: false, //是否开启上传
    percent: 0, //上传进度
    percentCount: 0,
  };
  if (file.size > chunkSize) options.showProgress = true;
  options.percent = 0;
  //1.文件标识 hash数据
  const hash: string = await calculateHashSample(file, chunkSize);
  //2.生成切片
  const chunkList = await setFileChunk(hash, file, chunkSize);

  const requestList: any = []; // 请求集合
  //3.生成分片上传请求
  if (chunkList.length > 0) {
    chunkList.forEach((item: any, index: number) => {
      const func = () => {
        const formData = new FormData();
        formData.append("chunkNumber", item.chunkNumber);
        formData.append("totalChunks", item.totalChunks);
        formData.append("chunkSize", item.chunkSize);
        formData.append("currentChunkSize", item.currentChunkSize);
        formData.append("totalSize", item.totalSize);
        formData.append("file", item.file);
        formData.append("identifier", item.identifier);
        formData.append("filename", item.filename);
        formData.append("ralativepath", item.ralativepath);
        return request.files
          .fastDfsChunkUploadUn(formData)
          .then((response: any) => {
            if (response.resp_code == 0) {
              // 避免上传成功后会删除切片改变 chunkList 的长度影响到 percentCount 的值
              if (options.percentCount === 0) {
                options.percentCount = 100 / chunkList.length;
              }
              // 改变进度
              options.percent += options.percentCount;
              onUploadProgress({ ...options }); //进度处理
              // 一旦上传成功就删除这一个 chunk，方便断点续传
              chunkList.splice(index, 1);
              //判断文件是否上传成功
              if (response.datas && response.datas.url) {
                funcCallback(response.datas.url, response.datas);
                options.showProgress = false;
              }
            }
          });
      };
      requestList.push(func);
    });
  }
  //4.开始处理文件分片上传处理
  let i = 0; // 记录发送的请求个数
  const send = async () => {
    if (i >= requestList.length) {
      //发送完毕
      options.showProgress = false;
      return;
    }
    await requestList[i]();
    i++;
    send();
  };
  send(); // 发送请求
}
